package com.rick.minio.service.impl;

import com.rick.minio.service.UploadService;
import io.minio.*;
import io.minio.http.Method;
import io.minio.messages.Bucket;
import io.minio.messages.DeleteError;
import io.minio.messages.DeleteObject;
import io.minio.messages.Item;
import jakarta.servlet.ServletOutputStream;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.FastByteArrayOutputStream;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Auther:wangyaozu
 * @Date: 2024/4/27 - 04 - 27 - 11:05
 * @Description: com.rick.minio.service
 * @version:1.0
 */
@Service
public class UploadServiceImpl implements UploadService {

    //MinIO的API请求地址
    //private final static String ENDPOINT = "http://127.0.0.1:9090";
    //用户名
    //private final static String USERNAME = "admin";
    //密码
    //private final static String PASSWORD = "1111";
    //桶名称
    private final static String BUCKETNAME = "group1";

    //回显路径
   //public final static String BASEURL = "http://127.0.0.1:9090/group1/";

    @Value("${minio.endpoint}")
    private String endPoint;
    @Value("${minio.username}")
    private String username;
    @Value("${minio.password}")
    private String password;
    @Value("${minio.bucketName}")
    private String bucketName;

    //单例加载
   //private final static MinioClient minioClient = MinioClient.builder().endpoint(ENDPOINT).credentials(USERNAME, PASSWORD).build();


    private MinioClient getMinioClient(){
        MinioClient minioClient = MinioClient.builder().endpoint(endPoint).credentials(username, password).build();
        return  minioClient;
    }



    /**
     * 创建存储bucket
     * @return Boolean
     */
    @Override
    public Boolean makeBucket(String bucketName) {
        MinioClient minioClient =  getMinioClient();
        try {
            minioClient.makeBucket(MakeBucketArgs.builder()
                    .bucket(bucketName)
                    .build());
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }
    /**
     * 删除存储bucket
     * @return Boolean
     */
    @Override
    public Boolean removeBucket(String bucketName) {
        MinioClient minioClient =  getMinioClient();
        try {
            minioClient.removeBucket(RemoveBucketArgs.builder()
                    .bucket(bucketName)
                    .build());
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }
    /**
     * 获取全部bucket
     */
    @Override
    public List<Bucket> getAllBuckets() {
        MinioClient minioClient =  getMinioClient();
        try {
            return minioClient.listBuckets();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 文件上传
     * @param file 文件
     * @return Boolean
     */
    @Override
    public String upload(MultipartFile file) {
        MinioClient minioClient =  getMinioClient();
        try {
            //MultipartFile转InputStream
            byte [] byteArr=file.getBytes();
            InputStream inputStream = new ByteArrayInputStream(byteArr);

            //获取文件名称
            String filename = file.getOriginalFilename();
            String prefix = filename.substring(filename.lastIndexOf(".") + 1);//后缀
            //根据当前时间生成文件夹
            Calendar calendar = Calendar.getInstance();
            Date time = calendar.getTime();
            // 2. 格式化系统时间--- 这里的时间格式可以根据自己的需要进行改变
            SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
            String buckfilename = format.format(time);

            String uuid= UUID.randomUUID().toString().replace("-","");//customer_YYYYMMDDHHMM
            String fileName = buckfilename+"/"+uuid+"."+prefix; //文件全路径

            PutObjectArgs objectArgs = PutObjectArgs.builder().bucket(BUCKETNAME).object(fileName)
                    .stream(inputStream,file.getSize(),-1).contentType(file.getContentType()).build();
            //文件名称相同会覆盖
            minioClient.putObject(objectArgs);
            return fileName;
        } catch (Exception e) {
            e.printStackTrace();
        }finally {

        }
        return "";
    }
    /**
     * 上传文件---直接传file
     *
     * @return
     */
    @Override
    public String upload(byte data[], String fileName) {
        MinioClient minioClient =  getMinioClient();
//        File file = byte2File(data,"D:\\lsfile",fileName);
        try {
//            MultipartFile multipartFile = getMultipartFile(file);
//            byte [] byteArr=multipartFile.getBytes();
            InputStream inputStream = new ByteArrayInputStream(data);
            //获取文件名称
            String prefix = fileName.substring(fileName.lastIndexOf(".") + 1);//后缀
            //根据当前时间生成文件夹
            Calendar calendar = Calendar.getInstance();
            Date time = calendar.getTime();
            // 2. 格式化系统时间--- 这里的时间格式可以根据自己的需要进行改变
            SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
            String buckfilename = format.format(time);

            String uuid= UUID.randomUUID().toString().replace("-","");//customer_YYYYMMDDHHMM
            fileName = buckfilename+"/"+uuid+"."+prefix; //文件全路径

            PutObjectArgs objectArgs = PutObjectArgs.builder().bucket(BUCKETNAME).object(fileName)
                    .stream(inputStream,data.length,-1).contentType("image/"+prefix).build();
            //文件名称相同会覆盖
            minioClient.putObject(objectArgs);
            return fileName;
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
        }
        return "";
    }

    /**
     * 预览图片
     * @param fileName
     * @return
     */
    @Override
    public String preview(String fileName){
        MinioClient minioClient =  getMinioClient();
        // 查看文件地址
        GetPresignedObjectUrlArgs build = new GetPresignedObjectUrlArgs().builder().bucket(BUCKETNAME).object(fileName).method(Method.GET).build();
        try {
            String url = minioClient.getPresignedObjectUrl(build);
            return url;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 文件下载
     * @param fileName 文件名称
     * @param res response
     * @return Boolean
     */
    @Override
    public void download(String fileName, HttpServletResponse res) {
        MinioClient minioClient =  getMinioClient();
        GetObjectArgs objectArgs = GetObjectArgs.builder().bucket(BUCKETNAME)
                .object(fileName).build();
        try (GetObjectResponse response = minioClient.getObject(objectArgs)){
            byte[] buf = new byte[1024];
            int len;
            try (FastByteArrayOutputStream os = new FastByteArrayOutputStream()){
                while ((len=response.read(buf))!=-1){
                    os.write(buf,0,len);
                }
                os.flush();
                byte[] bytes = os.toByteArray();
                res.setCharacterEncoding("utf-8");
                //设置强制下载不打开
                //res.setContentType("application/force-download");
                res.addHeader("Content-Disposition", "attachment;fileName=" + fileName);
                try (ServletOutputStream stream = res.getOutputStream()){
                    stream.write(bytes);
                    stream.flush();
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 查看文件对象
     * @return 存储bucket内文件对象信息
     */
    @Override
    public List<Item> listObjects() {
        MinioClient minioClient =  getMinioClient();
        Iterable<Result<Item>> results = minioClient.listObjects(
                ListObjectsArgs.builder().bucket(BUCKETNAME).build());
        List<Item> items = new ArrayList<>();
        try {
            for (Result<Item> result : results) {
                items.add(result.get());
            }
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
        return items;
    }

    /**
     * 删除
     * @param fileName
     * @return
     * @throws Exception
     */
    @Override
    public boolean remove(String fileName){
        MinioClient minioClient =  getMinioClient();
        try {
            minioClient.removeObject( RemoveObjectArgs.builder().bucket(BUCKETNAME).object(fileName).build());
        }catch (Exception e){
            return false;
        }
        return true;
    }

    /**
     * 批量删除文件对象（没测试）
     * @param objects 对象名称集合
     */
    @Override
    public Iterable<Result<DeleteError>> removeObjects(List<String> objects) {
        MinioClient minioClient =  getMinioClient();
        List<DeleteObject> dos = objects.stream().map(e -> new DeleteObject(e)).collect(Collectors.toList());
        Iterable<Result<DeleteError>> results = minioClient.removeObjects(RemoveObjectsArgs.builder().bucket(BUCKETNAME).objects(dos).build());
        return results;
    }



    /**
     * 得到文件流
     * @param url  网络图片URL地址
     * @return
     */
    public static byte[] getFileStream(String url){
        try {
            URL httpUrl = new URL(url);
            HttpURLConnection conn = (HttpURLConnection)httpUrl.openConnection();
            conn.setRequestMethod("GET");
            conn.setConnectTimeout(5 * 1000);
            InputStream inStream = conn.getInputStream();//通过输入流获取图片数据
            byte[] btImg = readInputStream(inStream);//得到图片的二进制数据
            return btImg;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 从输入流中获取数据
     * @param inStream 输入流
     * @return
     * @throws Exception
     */
    public static byte[] readInputStream(InputStream inStream) throws Exception{
        ByteArrayOutputStream outStream = new ByteArrayOutputStream();
        byte[] buffer = new byte[1024];
        int len = 0;
        while( (len=inStream.read(buffer)) != -1 ){
            outStream.write(buffer, 0, len);
        }
        inStream.close();
        return outStream.toByteArray();
    }

    /**
     * file转byte
     */
    public static byte[] file2byte(File file){
        byte[] buffer = null;
        try{
            FileInputStream fis = new FileInputStream(file);
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            byte[] b = new byte[1024];
            int n;
            while ((n = fis.read(b)) != -1)
            {
                bos.write(b, 0, n);
            }
            fis.close();
            bos.close();
            buffer = bos.toByteArray();
        }catch (FileNotFoundException e){
            e.printStackTrace();
        }
        catch (IOException e){
            e.printStackTrace();
        }
        return buffer;
    }

    /**
     * byte 转file
     */
    public static File byte2File(byte[] buf, String filePath, String fileName){
        BufferedOutputStream bos = null;
        FileOutputStream fos = null;
        File file = null;
        try{
            File dir = new File(filePath);
            if (!dir.exists() && dir.isDirectory()){
                dir.mkdirs();
            }
            file = new File(filePath + File.separator + fileName);
            fos = new FileOutputStream(file);
            bos = new BufferedOutputStream(fos);
            bos.write(buf);
        }catch (Exception e){
            e.printStackTrace();
        }
        finally{
            if (bos != null){
                try{
                    bos.close();
                }catch (IOException e){
                    e.printStackTrace();
                }
            }
            if (fos != null){
                try{
                    fos.close();
                }catch (IOException e){
                    e.printStackTrace();
                }
            }
        }
        return file;
    }
    /**
     * multipartFile转File
     **/
    public static File multipartFile2File(MultipartFile multipartFile){
        File file = null;
        if (multipartFile != null){
            try {
                file=File.createTempFile("tmp", null);
                multipartFile.transferTo(file);
                System.gc();
                file.deleteOnExit();
            }catch (Exception e){
                e.printStackTrace();
            }
        }
        return file;
    }
}
